﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Dynamic;

namespace WebQQ
{
    public class JSON : DynamicObject
    {
        private Dictionary<string, object> _values;
        private JSON()
        {
            _values = new Dictionary<string, object>();
        }

        public static dynamic Parse(string jsonString) 
        {
            try
            {
                JSON obj = new JSON();
                obj.Initialize(jsonString);
                return obj;
            }
            catch 
            {
                return null;
            }
        }

        public override bool TryGetMember(GetMemberBinder binder, out object result)
        {
            return _values.TryGetValue(binder.Name, out result);
        }

        private void Initialize(string jsonString)
        {
            jsonString = jsonString.Trim().Trim('\r', '\n');
            int len = jsonString.Length;
            if (String.IsNullOrEmpty(jsonString) || jsonString.Substring(0, 1) != "{" || jsonString.Substring(jsonString.Length - 1, 1) != "}")
            {
                return;
                //throw new ArgumentException("传入文本不符合Json格式!" + jsonString);
            }
            Stack<Char> stack = new Stack<char>();
            Stack<Char> stackType = new Stack<char>();
            StringBuilder sb = new StringBuilder();
            Char cur;
            bool convert = false;
            bool isValue = false;
            string last = null;
            for (int i = 1; i <= len - 2; i++)
            {
                cur = jsonString[i];
                if (cur == '}')
                {
                    ;
                }
                if (cur == ' ' && stack.Count == 0)
                {
                    ;
                }
                else if ((cur == '\'' || cur == '\"') && !convert && stack.Count == 0 && !isValue)
                {
                    sb.Length = 0;
                    stack.Push(cur);
                }
                else if ((cur == '\'' || cur == '\"') && !convert && stack.Count > 0 && stack.Peek() == cur && !isValue)
                {
                    stack.Pop();
                }
                else if ((cur == '[' || cur == '{') && stack.Count == 0)
                {
                    stackType.Push(cur == '[' ? ']' : '}');
                    sb.Append(cur);
                }
                else if ((cur == ']' || cur == '}') && stack.Count == 0 && stackType.Peek() == cur)
                {
                    stackType.Pop();
                    sb.Append(cur);
                }
                else if (cur == ':' && stack.Count == 0 && stackType.Count == 0 && !isValue)
                {
                    last = sb.ToString();
                    isValue = true;
                    sb.Length = 0;
                }
                else if (cur == ',' && stack.Count == 0 && stackType.Count == 0)
                {
                    if (last != null)
                    {
                        _values[last] = ParseValue(sb.ToString());
                    }
                    isValue = false;
                    sb.Length = 0;
                }
                else
                {
                    sb.Append(cur);
                }
            }
            if (sb.Length > 0 && last != null)
            {
                _values[last] = ParseValue(sb.ToString());
            }
        }

        /// <summary>
        /// Json字符串解析
        /// </summary>
        /// <param name="jsonString"></param>
        private object ParseValue(string jsonString)
        {
            if (String.IsNullOrEmpty(jsonString))
            {
                return null;
            }
            else
            {
                string first = jsonString.Substring(0, 1);
                string last = jsonString.Substring(jsonString.Length - 1, 1);
                if (first == "[" && last == "]")
                {
                    return this.ParseArray(jsonString);
                }
                else if (first == "{" && last == "}")
                {
                    return this.ParseObject(jsonString);
                }
                else if ((first == "'" || first == "\"") && first == last)
                {
                    return this.ParseString(jsonString);
                }
                else if (jsonString == "true" || jsonString == "false")
                {
                    return jsonString == "true" ? true : false;
                }
                else if (jsonString == "null")
                {
                    return null;
                }
                else
                {
                    return jsonString;
                }
            }
        }

        /// <summary>
        /// Json Array解析
        /// </summary>
        /// <param name="jsonString"></param>
        /// <returns></returns>
        private List<object> ParseArray(string jsonString)
        {
            List<object> list = new List<object>();
            int len = jsonString.Length;
            StringBuilder sb = new StringBuilder();
            Stack<Char> stack = new Stack<char>();
            Stack<Char> stackType = new Stack<Char>();
            bool conver = false;
            Char cur;
            for (int i = 1; i <= len - 2; i++)
            {
                cur = jsonString[i];
                if (Char.IsWhiteSpace(cur) && stack.Count == 0)
                {
                    ;
                }
                else if ((cur == '\'' && stack.Count == 0 && !conver && stackType.Count == 0) || (cur == '\"' && stack.Count == 0 && !conver && stackType.Count == 0))
                {
                    sb.Length = 0;
                    sb.Append(cur);
                    stack.Push(cur);
                }
                else if (cur == '\\' && stack.Count > 0 && !conver)
                {
                    sb.Append(cur);
                    conver = true;
                }
                else if (conver == true)
                {
                    conver = false;

                    if (cur == 'u')
                    {
                        sb.Append(new char[] { cur, jsonString[i + 1], jsonString[i + 2], jsonString[i + 3] });
                        i += 4;
                    }
                    else
                    {
                        sb.Append(cur);
                    }
                }
                else if ((cur == '\'' || cur == '\"') && !conver && stack.Count > 0 && stack.Peek() == cur && stackType.Count == 0)
                {
                    sb.Append(cur);
                    list.Add(ParseValue(sb.ToString()));
                    stack.Pop();
                }
                else if ((cur == '[' || cur == '{') && stack.Count == 0)
                {
                    if (stackType.Count == 0)
                    {
                        sb.Length = 0;
                    }
                    sb.Append(cur);
                    stackType.Push((cur == '[' ? ']' : '}'));
                }
                else if ((cur == ']' || cur == '}') && stack.Count == 0 && stackType.Count > 0 && stackType.Peek() == cur)
                {
                    sb.Append(cur);
                    stackType.Pop();
                    if (stackType.Count == 0)
                    {
                        list.Add(ParseValue(sb.ToString()));
                        sb.Length = 0;
                    }

                }
                else if (cur == ',' && stack.Count == 0 && stackType.Count == 0)
                {
                    if (sb.Length > 0)
                    {
                        list.Add(ParseValue(sb.ToString()));
                        sb.Length = 0;
                    }
                }
                else
                {
                    sb.Append(cur);
                }
            }
            if (stack.Count > 0 || stackType.Count > 0)
            {
                list.Clear();
                throw new ArgumentException("无法解析Json Array对象!");
            }
            else if (sb.Length > 0)
            {
                list.Add(ParseValue(sb.ToString()));
            }
            return list;
        }

        /// <summary>
        /// Json String解析
        /// </summary>
        /// <param name="jsonString"></param>
        /// <returns></returns>
        private string ParseString(string jsonString)
        {
            int len = jsonString.Length;
            StringBuilder sb = new StringBuilder();
            bool conver = false;
            Char cur;
            for (int i = 1; i <= len - 2; i++)
            {
                cur = jsonString[i];
                if (cur == '\\' && !conver)
                {
                    conver = true;
                }
                else if (conver == true)
                {
                    conver = false;
                    if (cur == '\\' || cur == '\"' || cur == '\'' || cur == '/')
                    {
                        sb.Append(cur);
                    }
                    else
                    {
                        if (cur == 'u')
                        {
                            String temp = new String(new char[] { jsonString[i + 1], jsonString[i + 2], jsonString[i + 3], jsonString[i + 4] });
                            sb.Append((char)Convert.ToInt32(temp, 16));
                            i += 4;
                        }
                        else
                        {
                            switch (cur)
                            {
                                case 'b':
                                    sb.Append('\b');
                                    break;
                                case 'f':
                                    sb.Append('\f');
                                    break;
                                case 'n':
                                    sb.Append('\n');
                                    break;
                                case 'r':
                                    sb.Append('\r');
                                    break;
                                case 't':
                                    sb.Append('\t');
                                    break;
                            }
                        }
                    }
                }
                else
                {
                    sb.Append(cur);
                }
            }
            return sb.ToString();
        }

        /// <summary>
        /// Json Object解析
        /// </summary>
        /// <param name="jsonString"></param>
        /// <returns></returns>
        private JSON ParseObject(string jsonString)
        {
            var json = new JSON();
            json.Initialize(jsonString);
            return json;
        }
    }
}
